package script
{
	/**
	 * 语法树
	 * @author blank
	 * 
	 */
	public class GenTree
	{
		private var _lex:Lex;
		
		private var index:int;
		
		private var curToken:Token;
		
		public var API:Object={};
		
		/**
		 * 
		 */
		public var imports:Object={};
		
		/**
		 * 函数节点
		 */
		public var motheds:Object={};
		
		/**
		 * 变量节点
		 */
		public var fields:Object={};
		
		public function GenTree()
		{
		}
		
		/**
		 * 定义
		 * @param lex
		 * @return 
		 * 
		 */
		public function declares(lex:Lex):GNode{
			_lex=lex;
			index=0;
			
			nextToken();
			
			var cnode:GNode=new GNode(GNodeType.Stms);
			var tnode:GNode;
			while(curToken){
				if(curToken.type == TokenType.keyvar){
					tnode=varStm();
					fields[tnode.name]=tnode;
					cnode.addChild(tnode);
				}else if(curToken.type == TokenType.keyfunction){
					tnode=funStm();
					motheds[tnode.name]=tnode;
				}else{
					tnode=stm();
					if(tnode.name){
						fields[tnode.name]=tnode;
					}
					cnode.addChild(tnode);
				}
			}
			return cnode;
		}
		
		/**
		 * 变量声明语句
		 * @return 
		 * 
		 */
		private function varStm():GNode{
			match(TokenType.keyvar);
			
			var tnode:GNode=new GNode(GNodeType.VarDecl,curToken);
			
			match(TokenType.ident);
			if(curToken.type == TokenType.Colon){
				//如果考虑语法解析的话。。。
				match(TokenType.Colon);
				tnode.varType=curToken.word;//变量类型
				match(curToken.type);
			}
			
			//如果是赋值运算
			if(curToken.type == TokenType.Assign){
				var cnode:GNode=new GNode(GNodeType.AssignStm,curToken);
				match(TokenType.Assign);
				cnode.addChild(tnode);
				cnode.addChild(expStm());
				if(curToken.type == TokenType.Semicolon){
					match(TokenType.Semicolon);
				}
				return cnode;
			}
			
			if(curToken && curToken.type == TokenType.Semicolon){
				match(TokenType.Semicolon);
			}
			return tnode;
		}
		
		/**
		 * 函数
		 * @return 
		 * 
		 */
		private function funStm():GNode{
			match(TokenType.keyfunction);
			var cnode:GNode=new GNode(GNodeType.FunDecl,curToken);
			cnode.varType="void";//函数默认的为无返回类型
			
			match(TokenType.ident);
			match(TokenType.LParent);
			cnode.addChild(ParamList());
			match(TokenType.RParent);
			
			if(curToken.type == TokenType.Colon){
				match(TokenType.Colon);
				cnode.varType=curToken.word;
				match(curToken.type);
			}
			
			cnode.addChild(stmList());
			return cnode;
		}
		
		/**
		 * 参数列表
		 * @return 
		 * 
		 */
		private function ParamList():GNode{
			var cnode:GNode=new GNode(GNodeType.Params);
			switch (curToken.type){
				case TokenType.ident:
					cnode.addChild(new GNode(GNodeType.VarID,curToken));
					match(TokenType.ident);
					if(curToken.type == TokenType.Colon){
						match(TokenType.Colon);
						cnode.varType=curToken.word;
						match(curToken.type);
					}
					
					while(curToken.type == TokenType.COMMA){
						match(TokenType.COMMA);
						cnode.addChild(new GNode(GNodeType.VarID,curToken));
						match(TokenType.ident);
						if(curToken.type==TokenType.Colon){
							match(TokenType.Colon);
							cnode.varType=curToken.word;
							match(curToken.type);	
						}
					}
					break;
				case TokenType.RParent:
					break;
				default:
					error();
			}
			return cnode;
		}
		
		/**
		 * 语句列表
		 * @return 
		 * 
		 */
		private function stmList():GNode{
			var cnode:GNode=new GNode(GNodeType.Stms);
			switch (curToken.type){
				case TokenType.LBRACE:
					match(TokenType.LBRACE);
					while(curToken.type != TokenType.RBRACE){
						cnode.addChild(stm());
					}
					match(TokenType.RBRACE);
					break;
				default:
					error();
			}
			return cnode;
		}
		
		/**
		 * 语句
		 * @return 
		 * 
		 */
		private function stm():GNode{
			var cnode:GNode;
			var tnode:GNode;
			switch (curToken.type){
				case TokenType.keyif:
					//总的，
					cnode=new GNode(GNodeType.IfElseStm);
					
					tnode=new GNode(GNodeType.ELSEIF);
					match(TokenType.keyif);
					match(TokenType.LParent);
					tnode.addChild(expStm());
					match(TokenType.RParent);
					tnode.addChild(stmList());
					
					cnode.addChild(tnode);
					
					//else / else if分支
					while(curToken.type == TokenType.keyelse){
						match(TokenType.keyelse);
						if(curToken.type==TokenType.keyif){//else if
							match(TokenType.keyif);
							
							tnode=new GNode(GNodeType.ELSEIF);
							match(TokenType.LParent);
							tnode.addChild(expStm());
							match(TokenType.RParent);
							tnode.addChild(stmList());
							cnode.addChild(tnode);
						}else{//else
							cnode.addChild(stmList());
						}
					}
					return cnode;
					
				case TokenType.keyfor:
					match(TokenType.keyfor);
					
					if(curToken.type == TokenType.keyeach){//for each
						match(TokenType.keyeach);
						match(TokenType.LParent);
						cnode=new GNode(GNodeType.ForEACHStm);
						if(curToken.type == TokenType.keyvar){//新建变量
							match(TokenType.keyvar);
						}
						if(curToken.type==TokenType.ident){
							cnode.addChild(new GNode(GNodeType.VarDecl,curToken));
							match(TokenType.ident);
							if(curToken.type == TokenType.Colon){
								match(TokenType.Colon);
								cnode.children[0].varType=curToken.word;
								match(curToken.type);
							}
							match(TokenType.COP,"in");
							
							cnode.addChild(expStm());
							match(TokenType.RParent);
							cnode.addChild(stmList());
						}else{
							throw Error("for each 匹配失败");
						}
					}else{
						match(TokenType.LParent);
						if(_lex.words[index+1].type == TokenType.COP || _lex.words[index+2].type == TokenType.COP){//for in
							cnode=new GNode(GNodeType.ForInStm);
							if(curToken.type==TokenType.keyvar){
								match(TokenType.keyvar);
							}
							if(curToken.type==TokenType.ident){
								cnode.addChild(new GNode(GNodeType.VarDecl,curToken));
								match(TokenType.ident);
								match(TokenType.COP,"in");
								
								cnode.addChild(expStm());
								match(TokenType.RParent);
								cnode.addChild(stmList());
							}else{
								throw Error("for in 匹配失败");
							}
						}else{//for
							cnode=new GNode(GNodeType.ForStm);
							cnode.addChild(stm());
							cnode.addChild(expStm());
							match(TokenType.Semicolon);
							cnode.addChild(stm());
							match(TokenType.RParent);
							cnode.addChild(stmList());
						}
					}
					return cnode;
					
				case TokenType.keywhile:
					cnode=new GNode(GNodeType.WhileStm);
					match(TokenType.keywhile);
					match(TokenType.LParent);
					cnode.addChild(expStm());
					match(TokenType.RParent);
					cnode.addChild(stmList());
					return cnode;
					
				case TokenType.keytry:
					cnode=new GNode(GNodeType.TRY);
					match(TokenType.keytry);
					cnode.addChild(stmList());//第一节点为执行部分
					if(curToken.type==TokenType.keycatch){
						tnode=new GNode(GNodeType.CATCH);
						match(TokenType.keycatch);//捕获错误
						match(TokenType.LParent);
						if(curToken.type==TokenType.ident){
							var tempnode:GNode=new GNode(GNodeType.VarID,curToken);
							tnode.addChild(tempnode);
							match(TokenType.ident);
							if(curToken.type==TokenType.Colon){//如果考虑语法解析的话。。。
								match(TokenType.Colon);
								tempnode.varType=curToken.word;
								//match(TokenType.ident);
								match(curToken.type);
							}
						}else{
							error();
						}
						match(TokenType.RParent);
						tnode.addChild(stmList());
						cnode.addChild(tnode);//第2节点为捕获部分
						if(curToken.type==TokenType.keyfinally){
							match(TokenType.keyfinally);//无论如何也要执行的
							cnode.addChild(stmList());//第2节点为捕获部分
						}
					}else{
						error();
					}
					return cnode;
					
				case TokenType.keyswitch:
					cnode=new GNode(GNodeType.SWITCH);
					match(TokenType.keyswitch);
					match(TokenType.LParent);
					cnode.addChild(expStm());//第一个节点为所需要判断的表达式
					match(TokenType.RParent);
					match(TokenType.LBRACE);
					//
					var ccc:int=0;//计数器，避免脚本分析陷入死循环
					while(curToken.type==TokenType.keycase){
						tnode=new GNode(GNodeType.CASE);
						match(TokenType.keycase);
						tnode.addChild(expStm());//第一个节点为所需要判断的表达式
						match(TokenType.Colon);
						//tnode.addChild(new GNode(GNodeType.Stms));
						ccc=0;
						while(curToken.type!=TokenType.keycase && curToken.type!=TokenType.keydefault && curToken.type!=TokenType.RBRACE){
							ccc++;
							if(tnode==null){
								trace("分析case出现严重错误");
							}
							tnode.addChild(stm());
							
							if(ccc>200){
								trace("分析case结构陷入死循环，请查看case部分代码");
								break;
							}
						}
						cnode.addChild(tnode);
					}
					if(curToken.type==TokenType.keydefault){
						tnode=new GNode(GNodeType.DEFAULT);
						match(TokenType.keydefault);
						match(TokenType.Colon);
						while(curToken.type!=TokenType.RBRACE){
							tnode.addChild(stm());
						}
						cnode.addChild(tnode);
					}
					match(TokenType.RBRACE);
					return cnode;
					
				case TokenType.keyvar:
					return varStm();
					
				case TokenType.ident:
					var tindex:int=index;
					tnode=ident();
					if(curToken.type == TokenType.Assign){//赋值语句
						cnode=new GNode(GNodeType.AssignStm,curToken);
						cnode.addChild(tnode);
						match(TokenType.Assign);
						cnode.addChild(expStm());
						if(curToken.type==TokenType.Semicolon){
							match(TokenType.Semicolon);
						}
					}else{//表达式
						index=tindex-1;
						nextToken();
						cnode=expStm();
						if(curToken && curToken.type==TokenType.Semicolon){
							match(TokenType.Semicolon);
						}
					}
					return cnode;
					
				case TokenType.constant:
				case TokenType.LParent:
				case TokenType.keynew:
				case TokenType.LOPNot:
				case TokenType.INCREMENT:
					cnode=expStm();
					if(curToken.type==TokenType.Semicolon){
						match(TokenType.Semicolon);
					}
					return cnode;
				case TokenType.MOP:
					if(curToken.word=="-"){
						cnode=expStm();
						if(curToken.type==TokenType.Semicolon){
							match(TokenType.Semicolon);
						}
						return cnode;
					}
					break;
				case TokenType.keyreturn:
					cnode=new GNode(GNodeType.ReturnStm,curToken);
					match(TokenType.keyreturn);
					if(curToken.type!=TokenType.Semicolon){
						cnode.addChild(expStm());
					}
					match(TokenType.Semicolon);
					return cnode;
					
				case TokenType.keyimport:
					return doImport();
					
				case TokenType.keycontinue:
					cnode=new GNode(GNodeType.CONTINUE);
					cnode.word=curToken.word;
					match(TokenType.keycontinue);
					if(curToken.type==TokenType.Semicolon){
						match(TokenType.Semicolon);
					}
					return cnode;
					
				case TokenType.keybreak:
					cnode=new GNode(GNodeType.BREAK);
					cnode.word=curToken.word;
					match(TokenType.keybreak);
					if(curToken.type==TokenType.Semicolon){
						match(TokenType.Semicolon);
					}
					return cnode;
					
				default:
					error();
					break;
			}
			return null;
		}
		
		/**
		 * 匹配,匹配成功则进入下一句,否则抛出错误信息
		 * @param type
		 * @param word
		 * 
		 */
		private function match(type:int,word:String=null):void{
			if(type==curToken.type && (word==null ||  curToken.word==word)){
				nextToken();
			}else{//匹配失败
				error();
			}
		}
		
		/**
		 * 执行包引入
		 * @return 
		 * 
		 */
		private function doImport():GNode{
			match(TokenType.keyimport);
			var vname_arr:Array=[];
			vname_arr[0]=curToken.word;
			match(TokenType.ident);
			//
			while(curToken.type==TokenType.DOT){
				match(TokenType.DOT);
				vname_arr.push(curToken.word);	
				match(TokenType.ident);
			}
			var cnode:GNode=new GNode(GNodeType.importStm);
			cnode.word=vname_arr.join(".");
			//TODO API[vname_arr[vname_arr.length-1]]=Script.getDef(cnode.word);
			
			imports[cnode.word]=true;
			if(curToken.type==TokenType.Semicolon){
				match(TokenType.Semicolon);
			}
			return cnode;
		}
		
		private function ident():GNode{
			var cnode:GNode=new GNode(GNodeType.IDENT);
			var tnode:GNode=new GNode(GNodeType.VarID,curToken);
			cnode.addChild(tnode);
			match(TokenType.ident);
			while(curToken.type == TokenType.LBRACKET || curToken.type == TokenType.DOT){
				if(curToken.type == TokenType.LBRACKET){
					match(TokenType.LBRACKET);
					tnode=new GNode(GNodeType.Index);
					tnode.addChild(expStm());
					cnode.addChild(tnode);
					match(TokenType.RBRACKET);
				}else {
					match(TokenType.DOT);
					tnode=new GNode(GNodeType.VarID,curToken);
					cnode.addChild(tnode);
					match(TokenType.ident);
				}
			}
			return cnode;
		}
		
		/**
		 * 表达式语句
		 * @return 
		 * 
		 */
		private function expStm():GNode{
			var tnode:GNode;
			var cnode:GNode;
			switch (curToken.type){
				case TokenType.ident:
				case TokenType.constant:
				case TokenType.LParent:
				case TokenType.keynew:
				case TokenType.LOPNot:
				case TokenType.INCREMENT:
					tnode=Term();
					if(curToken && curToken.type==TokenType.LOP){
						cnode=new GNode(GNodeType.LOP,curToken);	
						match(TokenType.LOP);
						cnode.addChild(tnode);
						cnode.addChild(expStm());
						return cnode;
					}else{
						return tnode;
					}
					break;
				case TokenType.MOP:
					if(curToken.word=="-"){
						tnode=Term();
						if(curToken.type==TokenType.LOP){
							cnode=new GNode(GNodeType.LOP,curToken);	
							match(TokenType.LOP);
							cnode.addChild(tnode);
							cnode.addChild(expStm());
							return cnode;
						}else{
							return tnode;
						}
					}
					break;
				case TokenType.LBRACKET:
					match(TokenType.LBRACKET);
					tnode=new GNode(GNodeType.newArray);
					if(curToken.type!=TokenType.RBRACKET){
						tnode.addChild(EXPList());
					}
					match(TokenType.RBRACKET);
					return tnode;
				case TokenType.LBRACE:
					match(TokenType.LBRACE);
					tnode=new GNode(GNodeType.newObject);
					if(curToken.type==TokenType.RBRACE){
						match(TokenType.RBRACE);
						return tnode;
					}
					do{
						if(curToken.type==TokenType.COMMA){
							match(TokenType.COMMA);
						}
						var cn:GNode=new GNode(GNodeType.VarID,curToken);
						cn.word=curToken.word;
						tnode.addChild(cn);
						match(TokenType.ident);
						match(TokenType.Colon);
						//
						if(curToken.type==TokenType.COMMA || curToken.type==TokenType.RBRACE){
							var tk:Token=new Token();
							tk.value="";
							tnode.addChild(new GNode(GNodeType.ConstID,tk));
						}else{
							tnode.addChild(expStm());
						}
					}while(curToken.type==TokenType.COMMA)
					match(TokenType.RBRACE);
					return tnode;
					break;
				default:
					error();
			}
			return null;
		}
		
		private function EXPList():GNode{
			var cnode:GNode=new GNode(GNodeType.EXPS);	
			switch (curToken.type){
				case TokenType.ident:
				case TokenType.constant:
				case TokenType.LParent:
				case TokenType.keynew:
				case TokenType.LOPNot:
				case TokenType.INCREMENT:
				case TokenType.LBRACKET:
				case TokenType.LBRACE:
					
					cnode.addChild(expStm());
					while(curToken.type==TokenType.COMMA){
						match(TokenType.COMMA);
						cnode.addChild(expStm());
					}
					return cnode;
					break;
				case TokenType.MOP:
					if(curToken.word=="-"){
						cnode.addChild(expStm());
						while(curToken.type==TokenType.COMMA){
							match(TokenType.COMMA);
							cnode.addChild(expStm());
						}
						return cnode;
					}
					break;
				default:
					error();
			}
			return null;
		}
		
		private function Term():GNode{
			var tnode:GNode;
			var cnode:GNode;
			switch (curToken.type){
				case TokenType.ident:
				case TokenType.constant:
				case TokenType.LParent:
				case TokenType.keynew:
				case TokenType.LOPNot:
				case TokenType.INCREMENT:
					tnode=facter();
					if(curToken && curToken.type==TokenType.COP){
						cnode=new GNode(GNodeType.COP,curToken);	
						match(TokenType.COP);
						cnode.addChild(tnode);
						cnode.addChild(Term());
						return cnode;
					}else{
						return tnode;
					}
					break;
				case TokenType.MOP:
					if(curToken.word=="-"){
						tnode=facter();
						if(curToken && curToken.type==TokenType.COP){
							cnode=new GNode(GNodeType.COP,curToken);	
							match(TokenType.COP);
							cnode.addChild(tnode);
							cnode.addChild(Term());
							return cnode;
						}else{
							return tnode;
						}
					}
					break;
				default:
					error();
			}
			return null;
		}
		
		private function facter():GNode{
			
			switch (curToken.type){
				case TokenType.ident:
				case TokenType.constant:
				case TokenType.LParent:
				case TokenType.keynew:
				case TokenType.LOPNot:
				case TokenType.INCREMENT:
					return MopFactor();
					//
					break;
				case TokenType.MOP:
					if(curToken.word=="-"){
						return MopFactor();
					}
					break;
				default:
					error();
			}
			return null;
		}
		
		private function MopFactor():GNode{
			var tnode:GNode;
			var cnode:GNode;
			var nodearr:Array=[];//输出后缀表达式
			var stack:Array=[];//符号堆栈
			nodearr.push(gene());
			var i:int;
			if(curToken && curToken.type==TokenType.MOP){
				while(curToken.type==TokenType.MOP){
					cnode=new GNode(GNodeType.MOP,curToken);
					var pri:int=priority(cnode);
					if(stack.length==0){
						//stack.push(cnode);
					}else{
						var len:int=stack.length-1;
						for(i=len;i>=0;i--){
							if(priority(stack[i] as GNode)>=pri){//压入到输出
								nodearr.push(stack.pop());
							}else{
								break;
							}
						}
					}
					stack.push(cnode);//符号入栈
					match(TokenType.MOP);
					nodearr.push(gene());
				}
				//5+10*(100-3);
				while(stack.length>0){
					nodearr.push(stack.pop());//压入到输出
				}
				
				//通过以上2步，已经做到了后缀表达式
				var ccc:String="";
				for(i=0;i<nodearr.length;i++){
					ccc+=(nodearr[i] as GNode).word+".";
				}
				//trace(ccc);
				//转为语法树返回
				
				for(i=0;i<nodearr.length;i++){
					if((nodearr[i] as GNode).children.length==0 && (nodearr[i] as GNode).type==GNodeType.MOP){//
						tnode=(nodearr[i] as GNode);
						var right:GNode=stack.pop();
						var left:GNode=stack.pop();
						tnode.addChild(left);
						tnode.addChild(right);
						stack.push(tnode);
					}else{
						stack.push(nodearr[i]);
					}
				}
				if(stack.length==1){
					//trace((stack[0] as GNode).toString());
					return stack[0];
				}else{
					error();//"错误的表达式"
				}
				
			}
			return nodearr[0];
		}
		
		private function priority(node:GNode):int{
			if(node.type == GNodeType.MOP){
				if(node.word == "+" || node.word == "-"){
					return 1;
				}
				return 2;
			}
			return 3;
		}
		
		private function gene():GNode{
			var cnode:GNode;
			var tnode:GNode;
			switch (curToken.type){
				case TokenType.constant:
					cnode=new GNode(GNodeType.ConstID,curToken);
					cnode.word=curToken.word;
					match(TokenType.constant);
					return cnode;
					break;
				case TokenType.LParent:
					match(TokenType.LParent);
					cnode=expStm();
					match(TokenType.RParent);
					return cnode;
					break;
				case TokenType.keynew:
					cnode=new GNode(GNodeType.newClass,curToken);
					match(TokenType.keynew);
					var id:GNode=new GNode(GNodeType.VarID,curToken);
					//
					cnode.addChild(id);
					match(TokenType.ident);
					while(curToken.type==TokenType.DOT){
						match(TokenType.DOT);
						id.word+="."+curToken.word;
						match(TokenType.ident);
					}
					match(TokenType.LParent);
					if(curToken.type!=TokenType.RParent){
						cnode.addChild(EXPList());
					}
					match(TokenType.RParent);
					return cnode;
					break;
				case TokenType.ident:
					tnode=ident();
					if(curToken.type==TokenType.LParent){
						cnode=new GNode(GNodeType.FunCall);
						cnode.addChild(tnode);
						match(TokenType.LParent);
						if(curToken.type!=TokenType.RParent){
							cnode.addChild(EXPList());
						}
						match(TokenType.RParent);
						return cnode;
					}else if(curToken.type==TokenType.INCREMENT){
						cnode=new GNode(GNodeType.INCREMENT);
						cnode.word=curToken.word;
						cnode.addChild(tnode);
						match(TokenType.INCREMENT);
						return cnode;
					}else{
						return tnode;
					}
					break;
				
				case TokenType.LOPNot:
					match(TokenType.LOPNot);
					tnode=gene();
					cnode=new GNode(GNodeType.LOPNot);
					cnode.word="!";
					cnode.addChild(tnode);
					return cnode;
				case TokenType.MOP:
					if(curToken.word=="-"){
						match(TokenType.MOP);
						tnode=gene();
						cnode=new GNode(GNodeType.Nagtive);
						cnode.word="-";
						cnode.addChild(tnode);
						return cnode;
					}
					break;
				case TokenType.INCREMENT:
					cnode=new GNode(GNodeType.PREINCREMENT);
					cnode.word=curToken.word;
					match(TokenType.INCREMENT);
					cnode.addChild(gene());
					return cnode;
				default:
					error();
			}
			return null;
		}
		
		private function nextToken():void{
			if(index < _lex.words.length){
				curToken=_lex.words[index++];
			}else{
				curToken=null;
			}
		}
		
		private function error():void{
			//throw new Error(name+"语法错误>行号:"+curToken.line+","+curToken.getLine()+"，单词："+curToken.word);
			throw new Error("语法错误!");
		}
	}
}